package com.example.api.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.api.dto.CreateOrderDTO;
import com.example.api.dto.GetConfirmInfoDTO;
import com.example.api.dto.OrderPaginateDTO;
import com.example.api.mapper.CarMapper;
import com.example.api.mapper.GoodsSpecMapper;
import com.example.api.mapper.OrderMapper;
import com.example.api.po.CarListPO;
import com.example.api.po.GoodsSpecConfirmInfoPO;
import com.example.api.po.GoodsSpecCreateOrderPO;
import com.example.api.po.OrderDetailPO;
import com.example.api.service.OrderGoodsSnapshotService;
import com.example.api.service.OrderService;
import com.example.api.vo.*;
import com.example.common.bo.PageParamBO;
import com.example.common.enums.OrderStatusEnum;
import com.example.common.exception.ServiceException;
import com.example.common.mapper.OrderGoodsSnapshotMapper;
import com.example.common.mapper.UserAddressMapper;
import com.example.common.po.*;
import com.example.common.utils.DomainUtil;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 *
 */
@Service("apiOrderServiceImpl")
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderPO>
        implements OrderService {
    @Autowired
    private HttpServletRequest httpServletRequest;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private GoodsSpecMapper goodsSpecMapper;
    @Autowired
    private CarMapper carMapper;
    @Autowired
    private OrderGoodsSnapshotMapper orderGoodsSnapshotMapper;
    @Autowired
    private OrderGoodsSnapshotService orderGoodsSnapshotService;
    @Autowired
    private UserAddressMapper userAddressMapper;
    @Autowired
    private WxPayService wxPayService;
    @Resource
    DataSourceTransactionManager dataSourceTransactionManager;
    @Resource
    TransactionDefinition transactionDefinition;
    @Autowired
    private AmqpTemplate rabbitTemplate;

    /**
     * 分页
     *
     * @param pageParamBO
     * @param orderPaginateDTO
     * @return
     */
    @Override
    public IPage getPaginateJoinByMap(PageParamBO pageParamBO, OrderPaginateDTO orderPaginateDTO) {
        return orderMapper.getPaginateJoinByMap(
                new Page<>(pageParamBO.getPageIndex(), pageParamBO.getPageSize()),
                (Integer) httpServletRequest.getSession().getAttribute("id"),
                orderPaginateDTO
        ).convert(po -> {
            OrderPaginateVO vo = new OrderPaginateVO();
            BeanUtils.copyProperties(po, vo);
            vo.setOrderGoodsSnapshot(po.getOrderGoodsSnapshot().stream().map(p->{
                OrderGoodsSnapshotVO v = new OrderGoodsSnapshotVO();
                BeanUtils.copyProperties(p, v);
                return v;
            }).collect(Collectors.toList()));
            return vo;
        });
    }

    /**
     * 详情
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderDetailVO getDetailJoinById(Integer orderId) {
        OrderDetailPO po = orderMapper.getDetailJoinById(orderId, (Integer) httpServletRequest.getSession().getAttribute("id"));
        if (Objects.isNull(po)) {
            throw new ServiceException("找不到资源", 104);
        }
        OrderDetailVO vo = new OrderDetailVO();
        BeanUtils.copyProperties(po, vo);
        vo.setOrderStatus(po.getOrderStatus().getKey());
        vo.setOrderGoodsSnapshot(po.getOrderGoodsSnapshot().stream().map(p -> {
            OrderDetailGoodsSnapshotVO v = new OrderDetailGoodsSnapshotVO();
            BeanUtils.copyProperties(p, v);
            v.setGoodsGallery(JSON.parseArray(p.getGoodsGallery()));
            v.setGallery(JSON.parseArray(p.getGallery()));
            return v;
        }).collect(Collectors.toList()));
        return vo;
    }

    /**
     * 确认订单
     *
     * @param getConfirmInfoDTO
     * @return
     */
    @Override
    public ConfirmInfoVO getConfirmInfo(GetConfirmInfoDTO getConfirmInfoDTO) {
        Integer userId = (Integer) httpServletRequest.getSession().getAttribute("id");
        List<ConfirmInfoGoodsVO> list = new ArrayList<>();
        if (!Objects.isNull(getConfirmInfoDTO.getGoodsId()) && !Objects.isNull(getConfirmInfoDTO.getSkuCode()) && !Objects.isNull(getConfirmInfoDTO.getQuantity())) {
            GoodsSpecConfirmInfoPO po = goodsSpecMapper.getGoodsSpecConfirmInfo(getConfirmInfoDTO.getGoodsId(), getConfirmInfoDTO.getSkuCode());
            if (Objects.isNull(po)) {
                throw new ServiceException("找不到资源", 104);
            }
            ConfirmInfoGoodsVO vo = new ConfirmInfoGoodsVO();
            BeanUtils.copyProperties(po, vo);
            vo.setQuantity(1);
            list.add(vo);
        } else {
            list = carMapper.getConfirmInfo(userId).stream().map(po -> {
                ConfirmInfoGoodsVO vo = new ConfirmInfoGoodsVO();
                BeanUtils.copyProperties(po, vo);
                return vo;
            }).collect(Collectors.toList());
        }
        ConfirmInfoVO vo = new ConfirmInfoVO();
        vo.setList(list);
        // 获取订单地址信息
        UserAddressPO po = userAddressMapper.selectOne(
                new QueryWrapper<UserAddressPO>()
                        .select("address_id", "province_id", "province_name", "city_id", "city_name", "district_id", "district_name", "name", "mobile", "full_address", "is_default")
                        .lambda()
                        .eq(UserAddressPO::getUserId, userId)
                        .orderByDesc(UserAddressPO::getIsDefault)
                        .orderByDesc(UserAddressPO::getAddressId)
                        .last("limit 1")
        );
        UserAddressDetailVO userAddressDetailVO = new UserAddressDetailVO();
        BeanUtils.copyProperties(po, userAddressDetailVO);
        vo.setUserAddress(userAddressDetailVO);
        return vo;
    }

    /**
     * 创建订单
     *
     * @param createOrderDto
     * @return
     */
    @Override
    public CreateOrderVO createOrder(CreateOrderDTO createOrderDto) {
        // 直接购买
        if (!Objects.isNull(createOrderDto.getGoodsId()) && !Objects.isNull(createOrderDto.getSkuCode()) && !Objects.isNull(createOrderDto.getQuantity())) {
            return buyNew(createOrderDto.getGoodsId(), createOrderDto.getSkuCode(), createOrderDto.getQuantity(), createOrderDto.getRemark());
        } else {
            return carSettlement(createOrderDto.getRemark());
        }
    }

    @Override
    public void pay(Integer orderId) {
        Integer userId = (Integer) httpServletRequest.getSession().getAttribute("id");
        String openid = (String) httpServletRequest.getSession().getAttribute("openid");
        OrderPO po = orderMapper.selectOne(new QueryWrapper<OrderPO>().lambda().eq(OrderPO::getOrderId,orderId).eq(OrderPO::getUserId,userId));
        if (Objects.isNull(po)) {
            throw new ServiceException("找不到资源", 104);
        }
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setBody("半夏商城："+po.getOrderCode());
            orderRequest.setOutTradeNo(po.getOrderCode());
            orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(po.getPaymentAmount().toString()));//元转成分
            orderRequest.setOpenid(openid);
            orderRequest.setSpbillCreateIp(httpServletRequest.getRemoteAddr());
            orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
            orderRequest.setNotifyUrl(DomainUtil.getCurrentDomain(httpServletRequest)+ "/com/example/api/notify/wechatPayNotify");
            WxPayMpOrderResult wxPayMpOrderResult = wxPayService.createOrder(orderRequest);
        } catch (WxPayException e) {
            throw new ServiceException(e.getReturnMsg(), 106);
        } catch (Exception e){
            throw new ServiceException(e.getMessage(), 106);
        }
    }

    /**
     * 取消订单
     *
     * @param orderId
     * @return
     */
    @Override
    public Integer cancel(Integer orderId) {
        Integer userId = (Integer) httpServletRequest.getSession().getAttribute("id");
        OrderPO data = orderMapper.selectOne(
                new QueryWrapper<OrderPO>()
                        .lambda()
                        .eq(OrderPO::getOrderId, orderId)
                        .eq(OrderPO::getUserId, userId)
                        .eq(OrderPO::getOrderStatus, OrderStatusEnum.WAIT_PAY.getKey())
        );
        if (Objects.isNull(data)) {
            throw new ServiceException("找不到资源", 104);
        }
        //开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            List<OrderGoodsSnapshotPO> orderGoodsSnapshotPOArrayList = orderGoodsSnapshotMapper.selectList(
                    new QueryWrapper<OrderGoodsSnapshotPO>()
                            .lambda()
                            .eq(OrderGoodsSnapshotPO::getOrderId, orderId)
            );
            // 补库存
            orderGoodsSnapshotPOArrayList.forEach(e -> {
                goodsSpecMapper.update(
                        new UpdateWrapper<GoodsSpecPO>()
                                .lambda()
                                .eq(GoodsSpecPO::getSkuCode, e.getSkuCode())
                                .setSql("store_count = store_count+" + e.getQuantity())
                );
            });
            // 更新状态
            Integer result = orderMapper.update(new UpdateWrapper<OrderPO>()
                    .lambda()
                    .eq(OrderPO::getOrderId, orderId)
                    .eq(OrderPO::getUserId, userId)
                    .eq(OrderPO::getOrderStatus, OrderStatusEnum.WAIT_PAY.getKey())
                    .set(OrderPO::getOrderStatus, OrderStatusEnum.CANCEL.getKey())
            );
            // 提交
            dataSourceTransactionManager.commit(transactionStatus);
            return result;
        } catch (Exception e) {
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ServiceException(e.getMessage(), 106);
        }
    }

    /**
     * 立即购买
     *
     * @param goodsId
     * @param skuCode
     * @param quantity
     * @return
     */
    private CreateOrderVO buyNew(Integer goodsId, String skuCode, Integer quantity, String remark) {
        Integer userId = (Integer) httpServletRequest.getSession().getAttribute("id");
        UserAddressPO userAddressPO = userAddressMapper.selectOne(new QueryWrapper<UserAddressPO>()
                .select("address_id", "province_id", "province_name", "city_id", "city_name", "district_id", "district_name", "name", "mobile", "full_address", "is_default")
                .lambda()
                .eq(UserAddressPO::getUserId, userId)
                .orderByDesc(UserAddressPO::getIsDefault)
                .orderByDesc(UserAddressPO::getAddressId)
                .last("limit 1"));
        if (Objects.isNull(userAddressPO)) {
            throw new ServiceException("缺少收货地址", 106);
        }
        //开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            GoodsSpecCreateOrderPO goodsSpec = goodsSpecMapper.getGoodsSpecCreateOrder(goodsId, skuCode);
            if (goodsSpec.getStoreCount() - quantity < 0) {
                throw new ServiceException("库存不足", 106);
            }
            // 扣除库存
            goodsSpecMapper.update(
                    new UpdateWrapper<GoodsSpecPO>()
                            .lambda()
                            .eq(GoodsSpecPO::getGoodsId, goodsId)
                            .eq(GoodsSpecPO::getSkuCode, skuCode)
                            .eq(GoodsSpecPO::getStatus, 1)
                            .setSql("store_count = store_count-" + quantity)
            );
            // 创建订单
            BigDecimal result = goodsSpec.getPrice().multiply(new BigDecimal(quantity)).setScale(2);
            OrderPO insertOrderPO = new OrderPO();
            BeanUtils.copyProperties(userAddressPO, insertOrderPO);
            insertOrderPO.setUserId(userId);
            // 收货地址信息
            insertOrderPO.setAddressName(userAddressPO.getName());
            insertOrderPO.setAddressMobile(userAddressPO.getMobile());
            insertOrderPO.setOrderAddress(userAddressPO.getProvinceName() + " " + userAddressPO.getCityName() + " " + userAddressPO.getDistrictName() + " " + userAddressPO.getFullAddress());
            insertOrderPO.setClientRemark(remark);
            // 创建订单信息
            insertOrderPO.setOrderCode("SN" + System.currentTimeMillis() + RandomUtil.randomNumbers(4));
            insertOrderPO.setOrderPrice(result);
            insertOrderPO.setPaymentAmount(result);
            insertOrderPO.setOrderStatus(OrderStatusEnum.WAIT_PAY);
            orderMapper.insert(insertOrderPO);
            // 创建快照
            OrderGoodsSnapshotPO orderGoodsSnapshotPOInsertPO = new OrderGoodsSnapshotPO();
            BeanUtils.copyProperties(goodsSpec, orderGoodsSnapshotPOInsertPO);
            orderGoodsSnapshotPOInsertPO.setUserId(userId);
            orderGoodsSnapshotPOInsertPO.setOrderId(insertOrderPO.getOrderId());
            orderGoodsSnapshotPOInsertPO.setQuantity(quantity);
            orderGoodsSnapshotMapper.insert(orderGoodsSnapshotPOInsertPO);
            //将消息发送到order队列
            rabbitTemplate.convertAndSend("ex.order", "order", insertOrderPO.getOrderId());
            // 提交
            dataSourceTransactionManager.commit(transactionStatus);
            CreateOrderVO vo = new CreateOrderVO();
            vo.setOrderId(insertOrderPO.getOrderId());
            return vo;
        } catch (Exception e) {
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ServiceException(e.getMessage(), 106);
        }
    }

    /**
     * 购物车结算
     *
     * @return
     */
    private CreateOrderVO carSettlement(String remark) {
        Integer userId = (Integer) httpServletRequest.getSession().getAttribute("id");
        UserAddressPO userAddressPO = userAddressMapper.selectOne(new QueryWrapper<UserAddressPO>()
                .select("address_id", "province_id", "province_name", "city_id", "city_name", "district_id", "district_name", "name", "mobile", "full_address", "is_default")
                .lambda()
                .eq(UserAddressPO::getUserId, userId)
                .orderByDesc(UserAddressPO::getIsDefault)
                .orderByDesc(UserAddressPO::getAddressId)
                .last("limit 1"));
        if (Objects.isNull(userAddressPO)) {
            throw new ServiceException("缺少收货地址", 106);
        }
        //开启事务
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            // 查询出所有选中的购物车
            List<CarListPO> carList = carMapper.selectByMapJoinGoods(userId);
            if (carList.size() == 0) {
                throw new ServiceException("创建失败，没有符合条件的数据", 106);
            }
            // 影响的carIds
            List<Integer> carIds = new ArrayList<>();
            // 合计金额
            BigDecimal orderPrice = new BigDecimal(0).setScale(2);
            // 快照列表
            List<OrderGoodsSnapshotPO> orderGoodsSnapshotPOList = new ArrayList<>();
            for (int i = 0; i < carList.size(); i++) {
                CarListPO e = carList.get(i);
                if (e.getStoreCount() - e.getQuantity() < 0) {
                    throw new ServiceException(e.getKeyName() + "库存不足", 106);
                }
                // 记录影响的id
                carIds.add(e.getCarId());
                //减掉库存
                goodsSpecMapper.update(
                        new UpdateWrapper<GoodsSpecPO>()
                                .lambda()
                                .eq(GoodsSpecPO::getSkuCode, e.getSkuCode())
                                .eq(GoodsSpecPO::getStatus, 1)
                                .setSql("store_count = store_count-" + e.getQuantity())
                );
                OrderGoodsSnapshotPO orderGoodsSnapshotPOInsertPO = new OrderGoodsSnapshotPO();
                BeanUtils.copyProperties(e, orderGoodsSnapshotPOInsertPO);
                orderGoodsSnapshotPOInsertPO.setUserId(userId);
                // 构建快照数据
                orderGoodsSnapshotPOList.add(orderGoodsSnapshotPOInsertPO);
                // 统计订单金额
                BigDecimal result = e.getPrice().multiply(new BigDecimal(e.getQuantity()));
                orderPrice = orderPrice.add(result);
            }
            // 删除购物车
            carMapper.delete(new QueryWrapper<CarPO>().lambda().in(CarPO::getCarId, carIds));
            // 创建订单
            OrderPO insertOrderPO = new OrderPO();
            BeanUtils.copyProperties(userAddressPO, insertOrderPO);
            insertOrderPO.setUserId(userId);
            // 收货地址信息
            insertOrderPO.setAddressName(userAddressPO.getName());
            insertOrderPO.setAddressMobile(userAddressPO.getMobile());
            insertOrderPO.setOrderAddress(userAddressPO.getProvinceName() + " " + userAddressPO.getCityName() + " " + userAddressPO.getDistrictName() + " " + userAddressPO.getFullAddress());
            // 创建订单信息
            insertOrderPO.setClientRemark(remark);
            insertOrderPO.setOrderCode("SN" + System.currentTimeMillis() + RandomUtil.randomNumbers(4));
            insertOrderPO.setOrderPrice(orderPrice);
            insertOrderPO.setPaymentAmount(orderPrice);
            insertOrderPO.setOrderStatus(OrderStatusEnum.WAIT_PAY);
            orderMapper.insert(insertOrderPO);
            // 保存快照
            orderGoodsSnapshotPOList.forEach(e -> e.setOrderId(insertOrderPO.getOrderId()));
            orderGoodsSnapshotService.saveBatch(orderGoodsSnapshotPOList);
            // 提交
            //将消息发送到order队列
            rabbitTemplate.convertAndSend("ex.order", "order", insertOrderPO.getOrderId());
            dataSourceTransactionManager.commit(transactionStatus);
            CreateOrderVO vo = new CreateOrderVO();
            vo.setOrderId(insertOrderPO.getOrderId());
            return vo;
        } catch (Exception e) {
            // 回滚
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new ServiceException(e.getMessage(), 106);
        }
    }
}




